package com.framework.test.utils;

import com.alibaba.fastjson.JSON;
import com.framework.test.context.GlobalContext;
import com.framework.test.enums.HttpStatus;
import com.framework.test.exceptions.AutomationException;
import com.framework.test.filters.LogFilter;
import io.restassured.RestAssured;
import io.restassured.builder.RequestSpecBuilder;
import io.restassured.config.EncoderConfig;
import io.restassured.config.RestAssuredConfig;
import io.restassured.http.ContentType;
import io.restassured.http.Cookie;
import io.restassured.http.Cookies;
import io.restassured.response.Response;
import io.restassured.specification.RequestSpecification;
import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import java.util.HashMap;
import java.util.Map;
import java.util.Properties;

import static io.restassured.RestAssured.given;

/**
 * REST API 工具类
 * 提供便捷的 HTTP 请求构建和执行功能
 * 支持自动配置加载、代理设置、SSL配置等
 */
public class RestUtil {

    private static final Logger logger = LogManager.getLogger(RestUtil.class);

    private RequestSpecBuilder requestSpecBuilder;
    private RequestSpecification requestSpecification;
    private Response apiResponse;

    private HttpStatus expectedStatusCode = HttpStatus.OK;
    private ContentType expectedResponseContentType = ContentType.JSON;

    public static RestUtil init() {
        return new RestUtil();
    }

    public RestUtil() {
        initializeRequestSpec();
    }

    /**
     * 自动初始化请求配置
     */
    private void initializeRequestSpec() {

        EncoderConfig encoderconfig = new EncoderConfig();
        requestSpecBuilder = new RequestSpecBuilder();

        try {
            String defaultBaseUri = ConfigurationManager.getProperty("app.url");
            if (StringUtils.isNotEmpty(defaultBaseUri)) {
                requestSpecBuilder.setBaseUri(defaultBaseUri);
            }
        } catch (AutomationException ignored) {
        }

        loadDefaultHeaders();
        loadProxyFromConfig();

        RestAssuredConfig config = RestAssured.config()
                .encoderConfig(encoderconfig.appendDefaultContentCharsetToContentTypeIfUndefined(false))
                .sslConfig(SSLUtil.getSSLConfig());

        requestSpecBuilder.setConfig(config);

    }

    /**
     * 从配置文件加载默认头部信息并应用GlobalContext占位符替换
     * 配置格式: headers.{headerName}={headerValue}
     * 支持占位符: ${variableName}
     */
    private void loadDefaultHeaders() {
        try {
            Properties headerProperties = ConfigurationManager.getPropertiesWithPrefix("headers");

            if (!headerProperties.isEmpty()) {
                Map<String, String> defaultHeaders = new HashMap<>();
                GlobalContext context = GlobalContext.getInstance();

                for (String headerName : headerProperties.stringPropertyNames()) {
                    String headerValue = headerProperties.getProperty(headerName);
                    if (headerValue != null) {
                        String processedValue = context.replacePlaceholders(headerValue);
                        defaultHeaders.put(headerName, processedValue);
                    }
                }
                requestSpecBuilder.addHeaders(defaultHeaders);
                logger.info("已加载默认头部信息: {}", defaultHeaders.keySet());
            }
        } catch (Exception e) {
            logger.error("加载默认头部信息失败: {}", e.getMessage());
        }
    }

    /**
     * 从配置文件加载代理设置
     * 支持的配置项：
     * - proxy.enabled=true/false (是否启用代理)
     * - proxy.host=代理主机地址
     * - proxy.port=代理端口
     * - proxy.scheme=http/https (可选，默认http)
     */
    private void loadProxyFromConfig() {
        try {
            // 检查是否启用代理
            boolean proxyEnabled = ConfigurationManager.getBooleanProperty("proxy.enabled", false);
            if (!proxyEnabled) {
                return;
            }

            // 获取代理配置
            String proxyHost = ConfigurationManager.getProperty("proxy.host", "");
            int proxyPort = ConfigurationManager.getIntegerProperty("proxy.port", 8080);
            String proxyScheme = ConfigurationManager.getProperty("proxy.scheme", "");

            if (proxyHost.trim().isEmpty()) {
                logger.error("代理配置错误: proxy.host 不能为空");
                return;
            }
            if (StringUtils.isNotEmpty(proxyScheme)) {
                requestSpecBuilder.setProxy(proxyHost, proxyPort, proxyScheme);
            } else {
                requestSpecBuilder.setProxy(proxyHost, proxyPort);
            }
            logger.info("已配置代理: " + proxyHost + ":" + proxyPort + ":" + proxyScheme);

        } catch (Exception e) {
            logger.error("加载代理配置失败: " + e.getMessage());
        }
    }

    /**
     * 手动设置基础URI，覆盖配置文件中的设置
     *
     * @param baseUri 要设置的基础URI
     * @return this
     */
    public RestUtil baseUri(String baseUri) {
        if (baseUri != null && !baseUri.trim().isEmpty()) {
            requestSpecBuilder.setBaseUri(baseUri);
        }
        return this;
    }

    /**
     * 定义API Path路径到请求配置
     *
     * @param path 请求路径
     * @return this
     */
    public RestUtil path(String path) {
        requestSpecBuilder.setBasePath(path);
        return this;
    }

    public RestUtil ssl(RestAssuredConfig sslConfig) {
        requestSpecBuilder.setConfig(sslConfig);
        return this;
    }

    public RestUtil proxy(String host, int port) {
        requestSpecBuilder.setProxy(host, port);
        return this;
    }

    public RestUtil proxy(String host, int port, String scheme) {
        requestSpecBuilder.setProxy(host, port, scheme);
        return this;
    }

    /**
     * 定义路径参数到请求配置
     *
     * @param key   参数名
     * @param value 参数值
     * @return this
     */
    public RestUtil pathParam(String key, String value) {
        requestSpecBuilder.addPathParam(key, value);
        return this;
    }

    /**
     * 定义查询参数到请求配置
     *
     * @param key   参数名
     * @param value 参数值
     * @return this
     */
    public RestUtil queryParam(String key, String value) {
        requestSpecBuilder.addQueryParam(key, value);
        return this;
    }

    /**
     * 定义内容类型头到请求配置
     *
     * @param contentType 内容类型
     * @return this
     */
    public RestUtil contentType(ContentType contentType) {
        requestSpecBuilder.setContentType(contentType);
        return this;
    }

    /**
     * 定义请求头到请求配置
     *
     * @param headers 请求头映射
     * @return this
     */
    public RestUtil headers(Map<String, String> headers) {
        requestSpecBuilder.addHeaders(headers);
        return this;
    }

    /**
     * 定义Cookies到请求配置
     *
     * @param cookies Cookie映射
     * @return this
     */
    public RestUtil cookies(Map<String, String> cookies) {
        requestSpecBuilder.addCookies(cookies);
        return this;
    }

    /**
     * 定义Cookies到请求配置
     *
     * @param cookies Cookies对象
     * @return this
     */
    public RestUtil cookies(Cookies cookies) {
        requestSpecBuilder.addCookies(cookies);
        return this;
    }

    /**
     * 定义Cookie到请求配置
     *
     * @param cookie Cookie对象
     * @return this
     */
    public RestUtil cookie(Cookie cookie) {
        requestSpecBuilder.addCookie(cookie);
        return this;
    }

    /**
     * 定义请求体到请求配置
     *
     * @param body 请求体对象
     * @return this
     */
    public RestUtil body(Object body) {
        requestSpecBuilder.setBody(body);
        return this;
    }

    /**
     * 定义API执行成功后用于验证的期望状态码
     *
     * @param expectedStatusCode 期望的状态码
     * @return this
     */
    public RestUtil expectedStatusCode(HttpStatus expectedStatusCode) {
        this.expectedStatusCode = expectedStatusCode;
        return this;
    }

    /**
     * 定义API执行成功后用于验证的期望响应内容类型
     *
     * @param contentType 期望的内容类型
     * @return this
     */
    public RestUtil expectedResponseContentType(ContentType contentType) {
        this.expectedResponseContentType = contentType;
        return this;
    }

    /**
     * 执行PUT请求
     * 构建请求配置并执行PUT请求，自动验证响应状态码和内容类型
     *
     * @return this
     */
    public RestUtil put() {
        requestSpecification = requestSpecBuilder.build();
        apiResponse =
                given()
                        .filter(new LogFilter())
                        .spec(requestSpecification)
                        .when()
                        .contentType(ContentType.JSON)
                        .put()
                        .then()
                        .assertThat()
                        .statusCode(expectedStatusCode.getCode())
                        .contentType(expectedResponseContentType)
                        .and()
                        .extract()
                        .response();

        return this;
    }

    /**
     * 执行DELETE请求
     * 构建请求配置并执行DELETE请求，自动验证响应状态码和内容类型
     *
     * @return this
     */
    public RestUtil delete() {
        requestSpecification = requestSpecBuilder.build();
        apiResponse =
                given()
                        .filter(new LogFilter())
                        .spec(requestSpecification)
                        .when()
                        .contentType(ContentType.JSON)
                        .delete()
                        .then()
                        .assertThat()
                        .statusCode(expectedStatusCode.getCode())
                        .contentType(expectedResponseContentType)
                        .and()
                        .extract()
                        .response();

        return this;
    }

    /**
     * 执行POST请求
     * 构建请求配置并执行POST请求，自动验证响应状态码和内容类型
     *
     * @return this
     */
    public RestUtil post() {
        requestSpecification = requestSpecBuilder.build();
        apiResponse =
                given()
                        .filter(new LogFilter())
                        .spec(requestSpecification)
                        .when()
                        .contentType(ContentType.JSON)
                        .post()
                        .then()
                        .assertThat()
                        .statusCode(expectedStatusCode.getCode())
                        .contentType(expectedResponseContentType)
                        .and()
                        .extract()
                        .response();

        return this;
    }

    /**
     * 执行GET请求
     * 构建请求配置并执行GET请求，自动验证响应状态码和内容类型
     *
     * @return this
     */
    public RestUtil get() {
        requestSpecification = requestSpecBuilder.build();
        apiResponse =
                given()
                        .filter(new LogFilter())
                        .spec(requestSpecification)
                        .when()
                        .get()
                        .then()
                        .assertThat()
                        .statusCode(expectedStatusCode.getCode())
                        .contentType(expectedResponseContentType)
                        .and()
                        .extract()
                        .response();

        return this;
    }

    /**
     * 获取API响应对象
     *
     * @return 响应对象
     */
    public Response response() {
        return apiResponse;
    }

    /**
     * 获取响应体的字符串
     *
     * @return 响应体字符串
     */
    public String getApiResponseAsString() {
        return apiResponse.asString();
    }

    /**
     * 将响应体转换为指定类型的POJO对象
     *
     * @param type 目标类型
     * @param <T>  泛型类型
     * @return 转换后的对象
     */
    public <T> T responseToPojo(Class<T> type) {
        return JSON.parseObject(apiResponse.asString(), type);
    }
}
